package com.sinosoft.platform.common.util;

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class DtoUtil {
	// 校验对象属性和表达式的一致性
	@SuppressWarnings({ "unchecked", "rawtypes" })
	private static Object validatePropertyExpressionConsistent(Object par, String type,
			String propertyName, String propertyValue, String pos)
			throws Exception {
		Class parClz = par.getClass();
//		System.out.println("class = " + parClz.getSimpleName());
		Field field = null;
		Type[] actualTypes = null;
		try {
			field = parClz.getDeclaredField(propertyName);
		} catch (Exception e) {
			throw new Exception("无法反射" + parClz.getName()
					+ "类的属性" + propertyName);
		}
		Class typeClz = field.getType(); // 获取属性所属类型
//		String setMethodName = "set"
//				+ propertyName.substring(0, 1).toUpperCase()
//				+ propertyName.substring(1);
		String getMethodName = "get"
				+ propertyName.substring(0, 1).toUpperCase()
				+ propertyName.substring(1);

		// 获取并判断泛型类型
		Type genericType = field.getGenericType();
		if (genericType instanceof ParameterizedType) {
			ParameterizedType pt = (ParameterizedType) genericType;
			// 获取实际传入的泛型类型
			actualTypes = pt.getActualTypeArguments();

		}
		// 校验属性是List类型
		if (List.class.isAssignableFrom(typeClz) && "list".equals(type)) {
			if (actualTypes.length > 0) {
				Class actualTypeClz = (Class) actualTypes[0];
				List list = null;
				try {
					list = (List) ClassInvokeUtil.reflectGetProperty(par, propertyName);
				} catch (Exception e) {
					throw new Exception("无法通过反射调用"
							+ parClz.getName() + "类的方法：" + getMethodName);
				}
				if (null == list) {
					list = new ArrayList();
					try {
						ClassInvokeUtil.reflectSetProperty(par, propertyName, list);
					} catch (Exception e) {
						e.printStackTrace();
					}
				}
				Object element = null;
				int index = Integer.valueOf(pos);
				if (list.size() > index && null != list.get(index)) {
					element = list.get(index);
				} else {
					// 如果提供了属性值则直接赋值
					if (null != propertyValue) {
						element = propertyValue;
						if (actualTypeClz != String.class) {
							try {
								element = StringUtil.transferString2PrimitiveType(propertyValue,
										actualTypeClz);
								
							} catch (Exception e) {
								e.printStackTrace();
							}
						}
					} else {
						try {
							element = actualTypeClz.newInstance();
						} catch (Exception e) {
							throw new Exception("无法为"
									+ parClz.getName() + "类型中List属性" + propertyName
									+ "创建" + actualTypeClz.getName() + "类型的元素");
						}
					}
					list.add(index, element);
				}
				return element;
			}
			throw new Exception("必须为" + parClz.getName()
					+ "类型中List属性" + propertyName + "设置泛型");

		}
		// 校验属性是Map类型
		else if (Map.class.isAssignableFrom(typeClz) && "map".equals(type)) {
			if (actualTypes.length > 1) {
				Class keyTypeClz = (Class) actualTypes[0];
				Class valueTypeClz = (Class) actualTypes[1];
				Map map = null;
				try {
					map = (Map) ClassInvokeUtil.reflectGetProperty(par, propertyName);
				} catch (Exception e) {
					throw new Exception("无法通过反射调用"
							+ parClz.getName() + "类的方法：" + getMethodName);
				}
				if (null == map) {
					map = new HashMap();
					try {
						ClassInvokeUtil.reflectSetProperty(par, propertyName, map);
					} catch (Exception e) {
						e.printStackTrace();
					}
				}
				Object key = pos;
				Object value = null;
				// 如果Map的key不是String类型，就把它转成其他基本类型（不支持对象类型）
				if (keyTypeClz != String.class) {
					try {
						key = StringUtil.transferString2PrimitiveType(pos,
								keyTypeClz);
					} catch (Exception e) {
						e.printStackTrace();
						throw new Exception("无法为"
								+ parClz.getName() + "类型中Map属性中"
								+ keyTypeClz.getName() + "类型的key设置值" + pos);
					}
					if (null == key) {
						throw new Exception("不允许为"
								+ parClz.getName() + "类型中Map属性中"
								+ keyTypeClz.getName() + "类型的key设值" + pos);
					}
				}
				Object mValue= map.get(key);
				boolean isSimpleType = ClassInvokeUtil.isSimpleTypeForMapValue(mValue.getClass());
				if (null != mValue && !isSimpleType) {
					value = mValue;
				} else {
					// 如果提供了属性值则直接赋值
					if (null != propertyValue) {
						value = propertyValue;
						if (valueTypeClz != String.class) {
							try {
								value = StringUtil.transferString2PrimitiveType(propertyValue,
										valueTypeClz);
							} catch (Exception e) {
								e.printStackTrace();
							}
						}
					} else {
						try {
							value = valueTypeClz.newInstance();
						} catch (Exception e) {
							throw new Exception("无法为"
									+ parClz.getName() + "类型中Map属性" + propertyName
									+ "创建value为" + valueTypeClz.getName() + "类型的元素");
						}
					}
					map.put(key, value);
				}
				return value;
			}
			throw new Exception("必须为" + parClz.getName()
					+ "类型中Map属性" + propertyName + "设置泛型");
		} else {
			// 认为是其他自定义类型
			Object sub = null;
			try {
				sub = ClassInvokeUtil.reflectGetProperty(par, propertyName);
			} catch (Exception e) {
				throw new Exception("无法通过反射调用" + parClz.getName()
						+ "类的方法：" + getMethodName);
			}
			if (null == sub || null != propertyValue) {
				// 如果提供了属性值则直接赋值
				if (null != propertyValue) {
					sub = propertyValue;
					
//					System.out.println(" typeClz = " + typeClz.getSimpleName());
					if (typeClz == BigDecimal.class) {
						// 将数值转换为BigDecimal
//						System.out.println("propertyValue = " + propertyValue);
						sub = new BigDecimal(propertyValue);
					} else if (typeClz == Date.class) {
						sub = DateUtil.parseDate(propertyValue, "yyyy-MM-dd");
					} else  {
						if (typeClz != String.class) {
							try {
								sub = StringUtil.transferString2PrimitiveType(propertyValue,
										typeClz);
							} catch (Exception e) {
								e.printStackTrace();
							}
						}
					}
				} else {
					try {
						sub = typeClz.newInstance();
					} catch (Exception e) {
						throw new Exception("无法为"
								+ parClz.getName() + "类型中" + typeClz.getName()
								+ "类型的属性创建实例");
					}
				}
				try {
					ClassInvokeUtil.reflectSetProperty(par, propertyName, sub);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
			return sub;
		}
	}
	
	// 验证表达式类型
	private static String[] validateExpression(String exp)
			throws Exception {
		List<String> index = StringUtil.dugSubstrings(exp, '[', ']');
		int beginIndex = exp.indexOf('[');
		if (beginIndex > 0 && index.size() == 1 && exp.endsWith("]")
				&& exp.indexOf("]") == exp.lastIndexOf("]")) {
			String propertyName = exp.substring(0, beginIndex);
			String pos = index.get(0);
			if (pos.startsWith("'") && pos.endsWith("'")) {
				List<String> key = StringUtil.dugSubstrings(pos, '\'', '\'');
				if (key.size() == 1 && !"".equals(key.get(0))) {
					return new String[] { "map", propertyName, key.get(0) };
				}
			}
			int i = -1;
			try {
				i = Integer.valueOf(pos);
			} catch (Exception e) {
				throw new Exception(exp + "无法解析为List或Map格式");
			}
			return new String[] { "list", propertyName, i + "" };
		} else if (exp.indexOf("[") != -1 || exp.indexOf("]") != -1
				|| exp.indexOf("'") != -1 || exp.indexOf("'") != -1) {
			throw new Exception(exp + "无法解析为List或Map格式");
		} else {
			return new String[] { "", exp, "" };
		}
	}
	
	@SuppressWarnings({ "unchecked", "rawtypes" })
    public static Object params2Object(Object obj, String name,
			Map<String, String[]> params, Class... clzs)
			throws Exception {
		// 先要对request中paramMap的key使用字典升序
		List<Map.Entry<String, String[]>> paramList = CollectionUtil.sortByKeys(params);
		Object par = null;
		for (int s = 0; s < paramList.size(); s++) {
			Map.Entry<String, String[]> entry = (Map.Entry<String, String[]>)paramList.get(s);
			String propertyName = entry.getKey();
			String[] propertyValues = entry.getValue();
			if (null == propertyValues || propertyValues.length == 0
					|| null == propertyValues[0]
					|| "".equals(propertyValues[0])) {
				continue;
			}
			String propertyValue = propertyValues[propertyValues.length - 1];
			// 字符串按.切割，同时过滤掉['和']之间的.号
			String[] subPropertyNames = StringUtil.splitStringByGap(
					propertyName, '.', "['", "']");
			// 第一个点号之前的内容
			String subPropertyName1 = "";
			if (subPropertyNames.length < 2) {
				subPropertyName1 = propertyName;
			} else {
				subPropertyName1 = subPropertyNames[0];
			}
			// 校验属性名称和第一个点号前的内容匹配
			if (!(subPropertyName1.equals(name) || subPropertyName1.indexOf(name + "[") != -1)) {
				continue;
			}
			String[] propertyInfo = validateExpression(subPropertyName1);
			if ("map".equals(propertyInfo[0])) {
				Map map = (Map) obj;
				String pos = propertyInfo[2];
				Object key = pos;
				if (clzs[0] != String.class) {
					try {
						key = StringUtil.transferString2PrimitiveType(pos,
								clzs[0]);
					} catch (Exception e) {
						e.printStackTrace();
					}
				}
				Object value = null;
				if (subPropertyNames.length < 2) {
					value = propertyValue;
					if (clzs[1] != String.class) {
						try {
							value = StringUtil.transferString2PrimitiveType(propertyValue,
									clzs[1]);
						} catch (Exception e) {
							e.printStackTrace();
						}
					}
				} else {
					if (null != map.get(key)) {
						value = map.get(key);
					} else {
						try {
							value = clzs[1].newInstance();
						} catch (Exception e) {
							e.printStackTrace();
						}
					}
				}
				map.put(key, value);
				par = value;
			} else if ("list".equals(propertyInfo[0])) {
				List list = (List) obj;
				String pos = propertyInfo[2];
				int index = Integer.valueOf(pos);
				Object element = null;
				if (subPropertyNames.length < 2) {
					element = propertyValue;
					if (clzs[0] != String.class) {
						try {
							element = StringUtil.transferString2PrimitiveType(propertyValue,
									clzs[0]);
							list.add(index, element);
						} catch (Exception e) {
							e.printStackTrace();
						}
					}
				} else {
					if (list.size() > index && null != list.get(index)) {
						element = list.get(index);
					} else {
						try {
							element = clzs[0].newInstance();
							list.add(index, element);
						} catch (Exception e) {
							e.printStackTrace();
						}
					}
				}
				par = element;
			} else {
				par = obj;
			}
			// 依次解析点号访问符以后的每个属性
			for (int i = 1; i < subPropertyNames.length - 1; i++) {
				String[] subPropertyInfos = validateExpression(subPropertyNames[i]);
				Object subObj = validatePropertyExpressionConsistent(par,
						subPropertyInfos[0], subPropertyInfos[1], null,
						subPropertyInfos[2]);
				par = subObj;
			}
			if (subPropertyNames.length >= 2) {
				// 获取表达式中最后一个属性信息并为赋最终值
				String[] lastSubPropertyInfos = validateExpression(subPropertyNames[subPropertyNames.length - 1]);
				validatePropertyExpressionConsistent(par, lastSubPropertyInfos[0],
						lastSubPropertyInfos[1], propertyValue,
						lastSubPropertyInfos[2]);
			}
		}
		return obj;
	}
}
